package cn.tworice.cryption.aop;

import cn.tworice.cryption.service.DataBaseCryption;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Aspect
@Component
public class DataBaseCryptionAspect {

    /**
     * 定义加密切入点，匹配实现DataBaseCryption接口的类的set方法
     */
    @Pointcut("execution(* cn.tworice..*.*(..)) && target(cn.tworice.cryption.service.DataBaseCryption) && execution(* set(..))")
    public void dataBaseEnCryptionMethods() {}

    /**
     * 定义解密切入点，匹配实现DataBaseCryption接口的类的getPage、info方法
     */
    @Pointcut("execution(* cn.tworice..*.*(..)) && target(cn.tworice.cryption.service.DataBaseCryption) && execution(* info(..))")
    public void dataBaseInfoDeCryptionMethods() {}

    @Pointcut("execution(* cn.tworice..*.*(..)) && target(cn.tworice.cryption.service.DataBaseCryption) && execution(* getPage(..))")
    public void dataBaseGetPageDeCryptionMethods() {}

    /**
     * 对set方法输入参数进行加密处理
     * @param joinPoint 切入点
     */
    @Around("dataBaseEnCryptionMethods()")
    public Object encryptInputValues(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        Object target = joinPoint.getTarget();
        // 获取当前切入点所在类的encrypt方法并调用
        Object encryptResult = target.getClass().getMethod("encrypt", Object.class).invoke(target, args[0]);
        args[0] = encryptResult;
        return joinPoint.proceed(args);
    }

    /**
     * 对info方法返回值进行解密处理
     */
    @Around("dataBaseInfoDeCryptionMethods()")
    public Object infoDecryptReturnValue(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        return joinPoint.getTarget().getClass().getMethod("decrypt", Object.class).invoke(joinPoint.getTarget(), result);
    }

    /**
     * 对getPage方法返回值进行解密处理
     */
    @Around("dataBaseGetPageDeCryptionMethods()")
    public Object getPageDecryptReturnValue(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        if (result instanceof Map) {
            Map<String, Object> map = (Map) result;
            List<Object> list = (List) map.get("list");

            for (Object item : list) {
                joinPoint.getTarget().getClass().getMethod("decrypt", Object.class).invoke(joinPoint.getTarget(), item);
            }
        }
        return result;
    }


}
